package com.lyf.scm.plan.domain.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.github.pagehelper.PageInfo;
import com.lyf.scm.common.enums.*;
import com.lyf.scm.common.model.BaseSearchDTO;
import com.lyf.scm.common.model.ExcelExportDataDTO;
import com.lyf.scm.common.model.SalesPlanSelectDTO;
import com.lyf.scm.common.util.AdvancedSearchUtil;
import com.lyf.scm.common.util.ExcelExportUtil;
import com.lyf.scm.common.util.date.MyDateUtil;
import com.lyf.scm.common.util.style.GeneralCellWriteHandler;
import com.lyf.scm.plan.api.dto.BaseSkuInfoDTO;
import com.lyf.scm.plan.api.dto.RoleAuthorityAreaDTO;
import com.lyf.scm.plan.api.dto.SalesPlanDTO;
import com.lyf.scm.plan.api.dto.SalesPlanInfoDTO;
import com.lyf.scm.plan.domain.remote.basedata.dto.AreaLevelDTO;
import com.lyf.scm.plan.domain.remote.basedata.dto.ChannelDTO;
import com.lyf.scm.plan.domain.remote.basedata.dto.StoreDTO;
import com.lyf.scm.plan.domain.remote.basedata.facade.BaseDataFacade;
import com.lyf.scm.plan.domain.repository.RoleAuthorityAreaRepository;
import com.lyf.scm.plan.domain.service.CommonService;
import com.lyf.scm.plan.domain.service.SalesPlanService;
import com.rome.arch.core.exception.RomeException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.InternalTerms;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.avg.InternalAvg;
import org.elasticsearch.search.aggregations.metrics.sum.InternalSum;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.stereotype.Service;

import javax.annotation.Nullable;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
import java.util.stream.Collectors;

import static com.lyf.scm.plan.domain.config.ExecutorConfig.EXECUTOR_CALL_API;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;

/**
 * @author Martin
 * @date 2020-10-26 15:53
 */
@Slf4j
@Service
public class SalesPlanServiceImpl implements SalesPlanService {

    private static final String SALES_PLAN_INDEX_NAME = "scm_sales_plan_index";
    private static final String GROUP_SKU_CODE = "skuCodeGroup";
    private static final String GROUP_AREA = "areaGroup";
    private static final String GROUP_PLAN_TYPE = "planTypeGroup";
    private static final String GROUP_CHANNEL_CODE = "channelCodeGroup";
    private static final String GROUP_DATE = "dateGroup";
    private SimpleDateFormat sdf_date = new SimpleDateFormat("yyyy-MM-dd");

    @Resource
    private ElasticsearchTemplate elasticsearchTemplate;
    @Resource
    private BaseDataFacade baseDataFacade;
    @Resource
    private CommonService commonService;
    @Resource(name = EXECUTOR_CALL_API)
    private Executor callApiExecutor;

    @Resource
    private RoleAuthorityAreaRepository roleAuthorityAreaRepository;

    @Override
    public PageInfo<SalesPlanInfoDTO> listWeekBySelective(SalesPlanDTO salesPlanDTO) {
        //生成周日期：如10.26-11.01
        List<String> dateList = getDateList(salesPlanDTO.getStartTime());
        // 构造需要返回的数据模型
        TermsAggregationBuilder aggregation = getTermsAggregation(salesPlanDTO.getConfirmLevel(), salesPlanDTO.getAreaAggregationLevel());
        // 多条件查询
        SearchQuery groupQuery = getSearchQuery(aggregation, salesPlanDTO);
        Aggregations aggregations = elasticsearchTemplate.query(groupQuery, SearchResponse::getAggregations);
        List<SalesPlanInfoDTO> salesPlanInfoDTOList = dealResult(aggregations, dateList);

        // 内存分页
        PageInfo<SalesPlanInfoDTO> pageInfo = paging(salesPlanInfoDTOList, salesPlanDTO.getPageNum(), salesPlanDTO.getPageSize());
        //补全数据
        completeData(pageInfo.getList(), dateList);
        return pageInfo;
    }

    private List<String> getDateList(Date startDate) {
        List<String> result = new ArrayList<>();
        String startDateStr = sdf_date.format(startDate);
        for (int i = 0; i < 14; i++) {
            String nextWeekDay = LocalDate.parse(startDateStr).plusWeeks(1).toString();
            result.add(getDateArea(startDateStr, nextWeekDay));
            startDateStr = nextWeekDay;
        }
        return result;
    }

    private String getDateArea(String startDateStr, String nextWeekDay) {
        String start = startDateStr.substring(startDateStr.indexOf("-") + 1).replace("-", ".");
        String end = nextWeekDay.substring(nextWeekDay.indexOf("-") + 1).replace("-", ".");
        return start + "-" + end;
    }

    /**
     * 构造结果模型
     * @param confirmLevel 确认等级，2、3、4，默认四级
     * @return
     */
    private TermsAggregationBuilder getTermsAggregation(int confirmLevel, int areaLevel) {
        // 计划类型分组
        TermsAggregationBuilder group0 = AggregationBuilders.terms(GROUP_PLAN_TYPE)
                .field("plan_type").size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        // 计划开始日期
        TermsAggregationBuilder group1 = AggregationBuilders.terms(GROUP_DATE)
                .field("start_date").size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        group1.subAggregation(group0);
        // sku分组
        TermsAggregationBuilder group2 = AggregationBuilders.terms(GROUP_SKU_CODE)
                .field("sku_key").size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        group2.subAggregation(group1);
        // 区域分组，要根据搜索条件判断是哪一级区域
        String areaField = "area";
        switch (areaLevel) {
            case 1:
                areaField = "province";
                break;
            case 2:
                areaField = "city";
                break;
            case 3:
                areaField = "district";
                break;
            case 4:
                areaField = "node_id";
                break;
        }
        TermsAggregationBuilder group3 = AggregationBuilders.terms(GROUP_AREA)
                .field(areaField).size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        group3.subAggregation(group2);
        // 渠道分组
        TermsAggregationBuilder group4 = AggregationBuilders.terms(GROUP_CHANNEL_CODE)
                .field("channel").size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        group4.subAggregation(group3);

        if (confirmLevel != 2 && confirmLevel != 3 && confirmLevel != 4) {
            confirmLevel = 4;
        }
        // 求和，具体字段根据传入条件做筛选
        // 销售计划量（除xxx外的计划量+预测量，根据计划类型做合并累加）
        group0.subAggregation(AggregationBuilders.sum("planQtySum").field("predict_sales"))
                // 直营预测计划类型的确认量，取值的字段通过等级计算
                .subAggregation(AggregationBuilders.sum("confirmQtySum").field("last_confirm_l" + confirmLevel))
                // 非直营计划类型的确认量
                .subAggregation(AggregationBuilders.sum("otherConfirmSum").field("last_confirm_l4"))
                // 直营预测计划类型的上次确认量（字段根据用户的等级来定，2级、3级、4级）
                .subAggregation(AggregationBuilders.sum("preConfirmSum").field("last_confirm_l" + confirmLevel))
                // 非直营预测的上次确认量
                .subAggregation(AggregationBuilders.sum("otherPreConfirmQtySum").field("last_confirm_l4"))
                // 单价平均
                .subAggregation(AggregationBuilders.avg("averagePriceAvg").field("averagePrice"))
                // 安全库存，取ss字段的平均值
                .subAggregation(AggregationBuilders.avg("ssQtyAvg").field("ss"))
                // 当前实时库存，期末库存
                .subAggregation(AggregationBuilders.avg("saleInventoryQtyAvg").field("saleInventory"));
        return group4;
    }

    private SearchQuery getSearchQuery(TermsAggregationBuilder aggregation, BaseSearchDTO baseSearchDTO) {
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        // 渠道条件
        List<String> permissionChannelList = baseSearchDTO.getPermissionChannelList();
        if (permissionChannelList == null || permissionChannelList.size() == 0) {
            throw new RomeException("无渠道权限");
        }
        // List<String> channelList = permissionChannelList.stream().map(SalesPlanSelectDTO::getCode).collect(Collectors.toList());
        // 查询条件没有渠道，取权限范围内的区域，传了的话取交集
        List<String> fatherChannelCodeList = baseSearchDTO.getChannelCodeList();
        if (fatherChannelCodeList != null && fatherChannelCodeList.size() > 0) {
            permissionChannelList = permissionChannelList.stream().filter(fatherChannelCodeList::contains).collect(Collectors.toList());
        }
        if (permissionChannelList.size() == 0) {
            throw new RomeException("无渠道权限");
        }
        setMultiConditions(boolQueryBuilder,"channel", baseSearchDTO.getChannelCodeList());
        // 计划类型
        setMultiConditions(boolQueryBuilder,"plan_type", baseSearchDTO.getTypeList());
        // 区域
        setAreaCondition(boolQueryBuilder, baseSearchDTO.getAreaCodeList());
        // 处理区域权限
        setAreaCondition(boolQueryBuilder, baseSearchDTO.getPermissionAreaList());
        // 品类
        setCategoryCondition(boolQueryBuilder, baseSearchDTO.getCategoryCodeList());
        // 商品
//        setMultiConditions(boolQueryBuilder,"sku_key", baseSearchDTO.getSkuCodeList());
        // 日期
        String startDate = sdf_date.format(baseSearchDTO.getStartTime());
        String endDate = MyDateUtil.getDateAfterWeek(startDate, 13);
        RangeQueryBuilder planStartDate = rangeQuery("start_date").gte(startDate).lte(endDate);
        boolQueryBuilder.must(planStartDate);
        return new NativeSearchQueryBuilder()
                .withQuery(boolQueryBuilder)
                .withIndices(SALES_PLAN_INDEX_NAME)
                .addAggregation(aggregation)
                .build();
    }

    /**
     * 设置查询条件
     * @param boolQueryBuilder
     * @param field
     * @param values
     */
    private void setMultiConditions(BoolQueryBuilder boolQueryBuilder, String field, List<String> values) {
        if (values == null || values.size() == 0) {
            return;
        }
        BoolQueryBuilder subBoolQueryBuilder = boolQuery();
        values.forEach(v -> subBoolQueryBuilder.should(QueryBuilders.matchQuery(field, v)));
        boolQueryBuilder.must(subBoolQueryBuilder);
    }

    private void setAreaCondition(BoolQueryBuilder boolQueryBuilder, List<SalesPlanSelectDTO> areaList) {
        if (areaList == null || areaList.size() == 0) {
            return;
        }
        BoolQueryBuilder subBoolQueryBuilder = boolQuery();
        areaList.forEach(v -> {
            String field = "province";
            switch (v.getLevel()) {
                case 1:
                    field = "province";
                    break;
                case 2:
                    field = "city";
                    break;
                case 3:
                    field = "district";
                    break;
                case 4:
                    field = "node_id";
                    break;
            }
            subBoolQueryBuilder.should(QueryBuilders.matchQuery(field, v.getCode()));
        });
        boolQueryBuilder.must(subBoolQueryBuilder);
    }

    private void setCategoryCondition(BoolQueryBuilder boolQueryBuilder, List<SalesPlanSelectDTO> categoryList) {
        if (categoryList == null || categoryList.size() == 0) {
            return;
        }
        BoolQueryBuilder subBoolQueryBuilder = boolQuery();
        categoryList.forEach(v -> {
            String field = "cate_l" + v.getLevel();
            if (v.getLevel() == 5) {
                field = "sku_key";
            }
            subBoolQueryBuilder.should(QueryBuilders.matchQuery(field, v.getCode()));
        });
        boolQueryBuilder.must(subBoolQueryBuilder);
    }

    /**
     * 解析返回结果
     *
     * @param aggregations
     * @return
     */
    private List<SalesPlanInfoDTO> dealResult(Aggregations aggregations, List<String> dateList) {
        List<SalesPlanInfoDTO> result = new ArrayList<>();
        //如果要返回分页数据，需要自己实现伪分页
        // 固定解析四级分组
        Map<String, Aggregations> channelAggregationsMap = getSubAggregations(aggregations, GROUP_CHANNEL_CODE);
        for(Map.Entry<String, Aggregations> channelEntry : channelAggregationsMap.entrySet()) {
            Map<String, Aggregations> areaAggregationsMap = getSubAggregations(channelEntry.getValue(), GROUP_AREA);
            for (Map.Entry<String, Aggregations> areaEntry : areaAggregationsMap.entrySet()) {
                // 地区，可能需要转换
                String area = areaEntry.getKey();
                Map<String, Aggregations> skuAggregationsMap = getSubAggregations(areaEntry.getValue(), GROUP_SKU_CODE);
                // sku维度拆分对象
                for (Map.Entry<String, Aggregations> skuEntry : skuAggregationsMap.entrySet()) {
                    // 定义返回对象
                    SalesPlanInfoDTO dto = new SalesPlanInfoDTO();
                    String skuCode = skuEntry.getKey();
                    //日期分组
                    Map<Long, Aggregations> dateAggregationsMap = getSubAggregations2(skuEntry.getValue(), GROUP_DATE);
                    Map<String, BigDecimal> planQtySumMap = new HashMap<>();
                    Map<String, BigDecimal> predictQtySumMap = new HashMap<>();
                    Map<String, BigDecimal> confirmQtySumMap = new HashMap<>();
                    Map<String, BigDecimal> preConfirmQtySumMap = new HashMap<>();
                    Map<String, BigDecimal> safetyStockQtyMap = new HashMap<>();
                    Map<String, BigDecimal> realTimeInventoryMap = new HashMap<>();
                    Map<String, BigDecimal> salesPlanAmountMap = new HashMap<>();
                    Map<String, BigDecimal> forecastPlanAmountMap = new HashMap<>();
                    for (Map.Entry<Long, Aggregations> dateEntry : dateAggregationsMap.entrySet()) {
                        // 日期
                        LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(
                                dateEntry.getKey() / 1000, 0, ZoneOffset.ofHours(8));
                        String currentDay = localDateTime.toLocalDate().toString();
                        String nextWeekDay = LocalDate.parse(currentDay).plusWeeks(1).toString();
                        String dateStr = this.getDateArea(currentDay, nextWeekDay);
                        // 销售计划量=所有除新品新店营销（已确定的量），按照渠道/商品/时间/区域汇总的计划量
                        BigDecimal salesPlanSum = BigDecimal.ZERO;
                        // 预测量=直营预测的预测量
                        BigDecimal predictQty = BigDecimal.ZERO;
                        // 确认量
                        BigDecimal confirmQty = BigDecimal.ZERO;
                        // 上次确认量
                        BigDecimal preConfirmQty = BigDecimal.ZERO;
                        // 安全库存
                        BigDecimal safetyStockQty = BigDecimal.ZERO;
                        // 当前实时库存
                        BigDecimal realTimeInventory = BigDecimal.ZERO;
                        // 平均单价
                        BigDecimal averagePriceAvg = BigDecimal.ZERO;
                        // 计划类型分组，计算指标
                        Map<String, Aggregations> planTypeAggregationsMap = getSubAggregations(dateEntry.getValue(), GROUP_PLAN_TYPE);
                        for (Map.Entry<String, Aggregations> planTypeEntry : planTypeAggregationsMap.entrySet()) {
                            String planType = planTypeEntry.getKey();
                            Map<String, Aggregation> sumMap = planTypeEntry.getValue().asMap();
                            //计划量
                            InternalSum planQtySum = (InternalSum) sumMap.get("planQtySum");
                            // 确认量
                            InternalSum confirmQtySum = (InternalSum) sumMap.get("confirmQtySum");
                            InternalSum otherConfirmSum = (InternalSum) sumMap.get("otherConfirmSum");
                            // 上次确认量
                            InternalSum preConfirmSum = (InternalSum) sumMap.get("preConfirmSum");
                            InternalSum otherPreConfirmQtySum = (InternalSum) sumMap.get("otherPreConfirmQtySum");
                            if (!SalesOtherTypeEnum.PLAN_ONE.getType().equals(planType)
                                    && !SalesOtherTypeEnum.PLAN_SIX.getType().equals(planType)
                                    && !SalesOtherTypeEnum.PLAN_SEVEN.getType().equals(planType)) {
                                salesPlanSum = salesPlanSum.add(internalSum2BigDecimal(planQtySum));
                            }
                            if ("17".equals(planType)) {
                                predictQty = predictQty.add(internalSum2BigDecimal(planQtySum));
                                confirmQty = confirmQty.add(internalSum2BigDecimal(confirmQtySum));
                                preConfirmQty = preConfirmQty.add(internalSum2BigDecimal(preConfirmSum));
                            } else {
                                confirmQty = confirmQty.add(internalSum2BigDecimal(otherConfirmSum));
                                preConfirmQty = preConfirmQty.add(internalSum2BigDecimal(otherPreConfirmQtySum));
                            }
                            // 安全库存
                            safetyStockQty = internalAvg2BigDecimal((InternalAvg) sumMap.get("ssQtyAvg"));
                            realTimeInventory = internalAvg2BigDecimal((InternalAvg) sumMap.get("saleInventoryQtyAvg"));
                            averagePriceAvg = internalAvg2BigDecimal((InternalAvg) sumMap.get("averagePriceAvg"));
                        }
                        // 把指标按照时间放入map，然后重新构造成list，空日期的补0
                        planQtySumMap.put(dateStr, salesPlanSum);
                        predictQtySumMap.put(dateStr, predictQty);
                        confirmQtySumMap.put(dateStr, confirmQty);
                        preConfirmQtySumMap.put(dateStr, preConfirmQty);
                        safetyStockQtyMap.put(dateStr, safetyStockQty);
                        realTimeInventoryMap.put(dateStr, realTimeInventory);
                        salesPlanAmountMap.put(dateStr, salesPlanSum.multiply(averagePriceAvg));
                        forecastPlanAmountMap.put(dateStr, predictQty.multiply(averagePriceAvg));
                    }
                    dto.setSalesPlanQty(getAllColumn(dateList, planQtySumMap));
                    dto.setForecastPlanQty(getAllColumn(dateList, predictQtySumMap));
                    dto.setConfirmQty(getAllColumn(dateList, confirmQtySumMap));
                    dto.setLastConfirmQty(getAllColumn(dateList, preConfirmQtySumMap));
                    dto.setSafetyStockQty(getAllColumn(dateList, safetyStockQtyMap));
                    dto.setRealTimeInventory(getAllColumn(dateList, realTimeInventoryMap));
                    dto.setSalesPlanAmount(getAllColumn(dateList, salesPlanAmountMap));
                    dto.setForecastPlanAmount(getAllColumn(dateList, forecastPlanAmountMap));
                    dto.setSkuCode(skuCode);
                    dto.setChannelCode(channelEntry.getKey());
                    dto.setDateList(dateList);
                    dto.setArea(area);
                    result.add(dto);
                }
            }
        }
        return result;
    }

    /**
     * 获取下级聚合数据
     * @param aggregations
     * @param subKey
     * @return 返回map，key是下级指标，值是聚合Aggregations对象
     */
    private Map<String, Aggregations> getSubAggregations(Aggregations aggregations, String subKey) {
        Map<String, Aggregation> aggregationMap = aggregations.asMap();
        StringTerms stringTerms = (StringTerms) aggregationMap.get(subKey);
        List<StringTerms.Bucket> buckets = stringTerms.getBuckets();
        return buckets.stream().collect(Collectors.toMap(bucket -> (String) bucket.getKey(), InternalTerms.Bucket::getAggregations));
    }

    private Map<Long, Aggregations> getSubAggregations2(Aggregations aggregations, String subKey) {
        Map<String, Aggregation> aggregationMap = aggregations.asMap();
        LongTerms longTerms = (LongTerms) aggregationMap.get(subKey);
        List<LongTerms.Bucket> buckets = longTerms.getBuckets();
        return buckets.stream().collect(Collectors.toMap(bucket -> (Long) bucket.getKey(), InternalTerms.Bucket::getAggregations));
    }

    private BigDecimal internalSum2BigDecimal(InternalSum sum) {
        if (sum == null) {
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(sum.getValue());
    }

    private BigDecimal internalAvg2BigDecimal(InternalAvg avg) {
        if (avg == null) {
            return BigDecimal.ZERO;
        }
        double val = "NaN".equals(String.valueOf(avg.getValue())) ? 0 : avg.getValue();
        return BigDecimal.valueOf(val);
    }

    /**
     * 构造全的列数据，某个时间列没有数据默认给0
     * @param dateColumnList
     * @param qtyMap
     * @return
     */
    private List<BigDecimal> getAllColumn(List<String> dateColumnList, Map<String, BigDecimal> qtyMap) {
        List<BigDecimal> list = new ArrayList<>(dateColumnList.size());
        dateColumnList.forEach(date -> {
            BigDecimal qty = qtyMap.get(date);
            list.add(qty == null ? BigDecimal.ZERO : qty);
        });
        return list;
    }

    /**
     * 补全数据
     */
    private void completeData(List<SalesPlanInfoDTO> list, List<String> dateList) {
        try {
            if (list == null || list.size() == 0) {
                return;
            }
            Set<String> channelCodeSet = new HashSet<>();
            Set<String> skuCodeSet = new HashSet<>();
            Set<String> lastAreaSet = new HashSet<>();
            list.forEach(salesPlanInfoDTO -> {
                channelCodeSet.add(salesPlanInfoDTO.getChannelCode());
                skuCodeSet.add(salesPlanInfoDTO.getSkuCode());
                lastAreaSet.add(getLastSubCode(salesPlanInfoDTO.getArea()));
            });
            // 批量取sku信息
            FutureTask<Map<String, BaseSkuInfoDTO>> skuInfoDTOMapTask = new FutureTask<>(() -> commonService.getCategoryInfoBySkuCodes(new ArrayList<>(skuCodeSet)));
            callApiExecutor.execute(skuInfoDTOMapTask);
            // 取渠道
            FutureTask<Map<String, String>> channelMapTask = new FutureTask<>(this::getChannelMap);
            callApiExecutor.execute(channelMapTask);
            Map<String, String> channelMap = channelMapTask.get();
            Map<String, BaseSkuInfoDTO> skuInfoDTOMap = skuInfoDTOMapTask.get();
            // 批量取区域
            Map<String, String> areaMap = parseArea(lastAreaSet);

            list.forEach(salesPlanInfoDTO -> {
                //渠道名称
                salesPlanInfoDTO.setChannel(channelMap.get(salesPlanInfoDTO.getChannelCode()));
                // 区域area
                String areaName = areaMap.get(getLastSubCode(salesPlanInfoDTO.getArea()));
                if (StringUtils.isNotEmpty(areaName)) {
                    salesPlanInfoDTO.setArea(areaName);
                }
                BaseSkuInfoDTO baseSkuInfoDTO = skuInfoDTOMap.get(salesPlanInfoDTO.getSkuCode());
                if (baseSkuInfoDTO != null) {
                    // 品类category
                    salesPlanInfoDTO.setCategory(baseSkuInfoDTO.getCategory());
                    // 商品名称skuName
                    salesPlanInfoDTO.setSkuName(baseSkuInfoDTO.getSkuName());
                }
                // 指标
                salesPlanInfoDTO.setActualSalesQty(getAllColumn(dateList, new HashMap<>()));
                salesPlanInfoDTO.setReservePurchaseQty(getAllColumn(dateList, new HashMap<>()));
                salesPlanInfoDTO.setNoFulfilPurchaseQty(getAllColumn(dateList, new HashMap<>()));
            });

        } catch (Exception e) {
            log.error("补全数据异常", e);
        }
    }

    private Map<String, String> getChannelMap() {
        List<ChannelDTO> list = baseDataFacade.getChannelByLevel(1);
        if (list != null && list.size() > 0) {
            return list.stream().collect(Collectors.toMap(ChannelDTO::getChannel
                    , ChannelDTO::getChannelName, (d1, d2) -> d1));
        }
        return new HashMap<>();
    }

    private String getLastSubCode(String areaCode) {
        if (StringUtils.isEmpty(areaCode)) {
            return "";
        }
        String lastSubCode = areaCode;
        if (areaCode.contains("/")) {
            lastSubCode = areaCode.substring(areaCode.lastIndexOf("/"));
        }
        return lastSubCode;
    }

    /**
     * 区域code解析成名称用/分隔，如江苏/南京市
     * @param lastAreaSet
     * @return
     */
    private Map<String, String> parseArea(Set<String> lastAreaSet) {
        // 省市区
        Set<String> areaSet = lastAreaSet.stream().filter(str -> str.length() > 4).collect(Collectors.toSet());
        Map<String, String> map = new HashMap<>();
        if (areaSet.size() > 0) {
            List<AreaLevelDTO> areaLevelDTOS = baseDataFacade.listRelationByArea(new ArrayList<>(areaSet));
            if (areaLevelDTOS != null && areaLevelDTOS.size() > 0) {
                for (AreaLevelDTO areaLevelDTO : areaLevelDTOS) {
                    String nameFullPath = areaLevelDTO.getNameFullPath();
                    if (StringUtils.isNotEmpty(nameFullPath)) {
                        nameFullPath = nameFullPath.substring(nameFullPath.indexOf("-") + 1).replace("-", "/");
                        map.put(areaLevelDTO.getCode(), nameFullPath);
                    }
                }
            }
        }
        // 门店
        Set<String> storeSet = lastAreaSet.stream().filter(str -> str.length() == 4).collect(Collectors.toSet());
        if (storeSet.size() > 0) {
            Map<String, String> storeInfoMap = getStoreInfoMap(storeSet);
            map.putAll(storeInfoMap);
        }
        return map;
    }

    /**
     * 取门店信息，拼省市区，如上海市/上海市/浦东新区/xxx门店
     * @param storeCodeList
     * @return
     */
    private Map<String, String> getStoreInfoMap(Set<String> storeCodeList) {
        Map<String, String> map = new HashMap<>();
        List<StoreDTO> storeDTOS = baseDataFacade.selectStoreListByCodes(new ArrayList<>(storeCodeList));
        if (storeDTOS != null && storeDTOS.size() > 0) {
            for (StoreDTO storeDTO : storeDTOS) {
                String province = storeDTO.getProvince();
                String city = storeDTO.getCity();
                String county = storeDTO.getCounty();
                String name = storeDTO.getName();
                String code = storeDTO.getCode();
                map.put(storeDTO.getCode(), province + "/" + city + "/" + county + "" + name + "/" + code);
            }
        }
        return map;
    }

    /**
     * 分页
     * @param list
     * @param pageNum
     * @param pageSize
     * @return
     */
    private PageInfo<SalesPlanInfoDTO> paging(List<SalesPlanInfoDTO> list, int pageNum, int pageSize) {
        int total = list.size();
        int start = Math.min((pageNum - 1) * pageSize, total);
        int end = Math.min(pageNum * pageSize, total);
        List<SalesPlanInfoDTO> subList = list.subList(start, end);
        PageInfo<SalesPlanInfoDTO> pageInfo = new PageInfo<>(subList);
        pageInfo.setPageNum(pageNum);
        pageInfo.setPageSize(pageSize);
        pageInfo.setTotal(total);
        return pageInfo;
    }

    @Override
    public List<SalesPlanInfoDTO> listAll(SalesPlanDTO salesPlanDTO) {
        salesPlanDTO.setPageNum(1);
        salesPlanDTO.setPageSize(Integer.MAX_VALUE);
        //生成周日期：如10.26-11.01
        List<String> dateList = getDateList(salesPlanDTO.getStartTime(), salesPlanDTO.getEndTime());
        // 构造需要返回的数据模型
        TermsAggregationBuilder aggregation = getTermsAggregation(salesPlanDTO.getConfirmLevel(), salesPlanDTO.getAreaAggregationLevel());
        // 多条件查询
        SearchQuery groupQuery = getSearchQuery(aggregation, salesPlanDTO);
        Aggregations aggregations = elasticsearchTemplate.query(groupQuery, SearchResponse::getAggregations);
        List<SalesPlanInfoDTO> salesPlanInfoDTOList = dealResult(aggregations, dateList);
        SalesPlanInfoDTO salesPlanInfoDTO = new SalesPlanInfoDTO();
        salesPlanInfoDTO.setDateList(dateList.stream().map(str -> str.split("-")[0]).collect(Collectors.toList()));
        // 合并到日期维度
        if (salesPlanInfoDTOList.size() > 0) {
            for (SalesPlanInfoDTO dto : salesPlanInfoDTOList) {
                salesPlanInfoDTO.setSalesPlanQty(addList(salesPlanInfoDTO.getSalesPlanQty(), dto.getSalesPlanQty()));
                salesPlanInfoDTO.setForecastPlanQty(addList(salesPlanInfoDTO.getForecastPlanQty(), dto.getForecastPlanQty()));
                salesPlanInfoDTO.setConfirmQty(addList(salesPlanInfoDTO.getConfirmQty(), dto.getConfirmQty()));
                salesPlanInfoDTO.setLastConfirmQty(addList(salesPlanInfoDTO.getLastConfirmQty(), dto.getLastConfirmQty()));
                salesPlanInfoDTO.setSafetyStockQty(addList(salesPlanInfoDTO.getSafetyStockQty(), dto.getSafetyStockQty()));
                salesPlanInfoDTO.setRealTimeInventory(addList(salesPlanInfoDTO.getRealTimeInventory(), dto.getRealTimeInventory()));
                salesPlanInfoDTO.setSalesPlanAmount(addList(salesPlanInfoDTO.getSalesPlanAmount(), dto.getSalesPlanAmount()));
                salesPlanInfoDTO.setForecastPlanAmount(addList(salesPlanInfoDTO.getForecastPlanAmount(), dto.getForecastPlanAmount()));
            }
        }
        //TODO
        salesPlanInfoDTO.setReservePurchaseQty(getAllColumn(dateList, new HashMap<>()));
        salesPlanInfoDTO.setActualSalesQty(getAllColumn(dateList, new HashMap<>()));
        salesPlanInfoDTO.setNoFulfilPurchaseQty(getAllColumn(dateList, new HashMap<>()));
        return Arrays.asList(salesPlanInfoDTO);
    }

    private List<BigDecimal> addList(@Nullable  List<BigDecimal> source, List<BigDecimal> target) {
        if (source == null) {
            return target;
        }
        for (int i = 0; i < source.size(); i++) {
            source.set(i, source.get(i).add(target.get(i)));
        }
        return source;
    }

    private List<String> getDateList(Date startDate, Date endDate) {
        List<String> result = new ArrayList<>();
        LocalDate startLocalDate = LocalDateTime.ofInstant(startDate.toInstant(), ZoneId.systemDefault()).toLocalDate();
        LocalDate endLocalDate = LocalDateTime.ofInstant(endDate.toInstant(), ZoneId.systemDefault()).toLocalDate();
        while (startLocalDate.compareTo(endLocalDate) == -1) {
            LocalDate nextWeekDay = startLocalDate.plusWeeks(1);
            result.add(getDateArea(startLocalDate.toString(), nextWeekDay.toString()));
            startLocalDate = nextWeekDay;
        }
        return result;
    }

    public List<SalesPlanInfoDTO> listAll_bak(SalesPlanDTO salesPlanDTO) {
        // 处理权限
        List<String> dateList = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("MM.dd");
        for (Map<String, Date> map : salesPlanDTO.getWeekDateList()) {
            Date date = map.get("startTime");
            String day = sdf.format(date);
            dateList.add(day);
        }

        // 构造需要返回的数据模型
        TermsAggregationBuilder aggregation = getTermsAggregation2(salesPlanDTO.getConfirmLevel());
        // 多条件查询
        SearchQuery groupQuery = getSearchQuery(aggregation, salesPlanDTO);
        Aggregations aggregations = elasticsearchTemplate.query(groupQuery, SearchResponse::getAggregations);
        List<SalesPlanInfoDTO> salesPlanInfoDTOList = dealResult2(aggregations, dateList);

        //补全数据
//        completeData2(salesPlanInfoDTOList, dateList);
        for (SalesPlanInfoDTO salesPlanInfoDTO : salesPlanInfoDTOList) {
            salesPlanInfoDTO.setSalesPlanAmount(getAllColumn(dateList, new HashMap<>()));
            salesPlanInfoDTO.setForecastPlanAmount(getAllColumn(dateList, new HashMap<>()));
            salesPlanInfoDTO.setReservePurchaseQty(getAllColumn(dateList, new HashMap<>()));
            salesPlanInfoDTO.setActualSalesQty(getAllColumn(dateList, new HashMap<>()));
            salesPlanInfoDTO.setNoFulfilPurchaseQty(getAllColumn(dateList, new HashMap<>()));
        }
        return salesPlanInfoDTOList;
    }

    /**
     * 构造结果模型
     * @param confirmLevel 确认等级，2、3、4，默认四级
     * @return
     */
    private TermsAggregationBuilder getTermsAggregation2(int confirmLevel) {
        // 计划类型分组
        TermsAggregationBuilder group0 = AggregationBuilders.terms(GROUP_PLAN_TYPE)
                .field("plan_type").size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        // 计划开始日期
        TermsAggregationBuilder group1 = AggregationBuilders.terms(GROUP_DATE)
                .field("start_date").size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        group1.subAggregation(group0);
        // sku分组
        TermsAggregationBuilder group2 = AggregationBuilders.terms(GROUP_SKU_CODE)
                .field("sku_key").size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        group2.subAggregation(group1);
        // 渠道分组
        TermsAggregationBuilder group3 = AggregationBuilders.terms(GROUP_CHANNEL_CODE)
                .field("channel").size(Integer.MAX_VALUE).shardSize(Integer.MAX_VALUE);
        group3.subAggregation(group2);

        if (confirmLevel != 2 && confirmLevel != 3 && confirmLevel != 4) {
            confirmLevel = 4;
        }
        // 求和，具体字段根据传入条件做筛选
        // 销售计划量（除xxx外的计划量+预测量，根据计划类型做合并累加）
        group0.subAggregation(AggregationBuilders.sum("planQtySum").field("predict_sales"))
                // 直营预测计划类型的确认量，取值的字段通过等级计算
                .subAggregation(AggregationBuilders.sum("confirmQtySum").field("last_confirm_l" + confirmLevel))
                // 非直营计划类型的确认量
                .subAggregation(AggregationBuilders.sum("otherConfirmSum").field("last_confirm_l4"))
                // 直营预测计划类型的上次确认量（字段根据用户的等级来定，2级、3级、4级）
                .subAggregation(AggregationBuilders.sum("preConfirmSum").field("last_confirm_l" + confirmLevel))
                // 非直营预测的上次确认量
                .subAggregation(AggregationBuilders.sum("otherPreConfirmQtySum").field("last_confirm_l4"))
                // 安全库存，取ss字段的平均值
                .subAggregation(AggregationBuilders.avg("ssQtyAvg").field("ss"))
                // 当前实时库存，期末库存
                .subAggregation(AggregationBuilders.avg("saleInventoryQtyAvg").field("saleInventory"));
        return group3;
    }

    private List<SalesPlanInfoDTO> dealResult2(Aggregations aggregations, List<String> dateList) {
        // 定义返回对象
        SalesPlanInfoDTO dto = new SalesPlanInfoDTO();
        //日期分组
        Map<Long, Aggregations> dateAggregationsMap = getSubAggregations2(aggregations, GROUP_DATE);
        Map<String, BigDecimal> planQtySumMap = new HashMap<>();
        Map<String, BigDecimal> predictQtySumMap = new HashMap<>();
        Map<String, BigDecimal> confirmQtySumMap = new HashMap<>();
        Map<String, BigDecimal> preConfirmQtySumMap = new HashMap<>();
        Map<String, BigDecimal> safetyStockQtyMap = new HashMap<>();
        Map<String, BigDecimal> realTimeInventoryMap = new HashMap<>();
        for (Map.Entry<Long, Aggregations> dateEntry : dateAggregationsMap.entrySet()) {
            // 日期
            LocalDateTime localDateTime = LocalDateTime.ofEpochSecond(
                    dateEntry.getKey() / 1000, 0, ZoneOffset.ofHours(8));
            String dateStr = localDateTime.format(DateTimeFormatter.ofPattern("MM.dd"));
            // 销售计划量=所有除新品新店营销（已确定的量），按照渠道/商品/时间/区域汇总的计划量
            BigDecimal salesPlanSum = BigDecimal.ZERO;
            // 预测量=直营预测的预测量
            BigDecimal predictQty = BigDecimal.ZERO;
            // 确认量
            BigDecimal confirmQty = BigDecimal.ZERO;
            // 上次确认量
            BigDecimal preConfirmQty = BigDecimal.ZERO;
            // 安全库存
            BigDecimal safetyStockQty = BigDecimal.ZERO;
            // 当前实时库存
            BigDecimal realTimeInventory = BigDecimal.ZERO;
            // 计划类型分组，计算指标
            Map<String, Aggregations> planTypeAggregationsMap = getSubAggregations(dateEntry.getValue(), GROUP_PLAN_TYPE);
            for (Map.Entry<String, Aggregations> planTypeEntry : planTypeAggregationsMap.entrySet()) {
                String planType = planTypeEntry.getKey();
                Map<String, Aggregation> sumMap = planTypeEntry.getValue().asMap();
                //计划量
                InternalSum planQtySum = (InternalSum) sumMap.get("planQtySum");
                // 确认量
                InternalSum confirmQtySum = (InternalSum) sumMap.get("confirmQtySum");
                InternalSum otherConfirmSum = (InternalSum) sumMap.get("otherConfirmSum");
                // 上次确认量
                InternalSum preConfirmSum = (InternalSum) sumMap.get("preConfirmSum");
                InternalSum otherPreConfirmQtySum = (InternalSum) sumMap.get("otherPreConfirmQtySum");
                if (!SalesOtherTypeEnum.PLAN_ONE.getType().equals(planType)
                        && !SalesOtherTypeEnum.PLAN_SIX.getType().equals(planType)
                        && !SalesOtherTypeEnum.PLAN_SEVEN.getType().equals(planType)) {
                    salesPlanSum = salesPlanSum.add(internalSum2BigDecimal(planQtySum));
                }
                if ("17".equals(planType)) {
                    predictQty = predictQty.add(internalSum2BigDecimal(planQtySum));
                    confirmQty = confirmQty.add(internalSum2BigDecimal(confirmQtySum));
                    preConfirmQty = preConfirmQty.add(internalSum2BigDecimal(preConfirmSum));
                } else {
                    confirmQty = confirmQty.add(internalSum2BigDecimal(otherConfirmSum));
                    preConfirmQty = preConfirmQty.add(internalSum2BigDecimal(otherPreConfirmQtySum));
                }
                // 安全库存，相加求平均值
                safetyStockQty = internalAvg2BigDecimal((InternalAvg) sumMap.get("ssQtyAvg"));
                realTimeInventory = internalAvg2BigDecimal((InternalAvg) sumMap.get("saleInventoryQtyAvg"));
            }
            // 把指标按照时间放入map，然后重新构造成list，空日期的补0
            planQtySumMap.put(dateStr, salesPlanSum);
            predictQtySumMap.put(dateStr, predictQty);
            confirmQtySumMap.put(dateStr, confirmQty);
            preConfirmQtySumMap.put(dateStr, preConfirmQty);
            safetyStockQtyMap.put(dateStr, safetyStockQty);
            realTimeInventoryMap.put(dateStr, realTimeInventory);
        }
        dto.setSalesPlanQty(getAllColumn(dateList, planQtySumMap));
        dto.setForecastPlanQty(getAllColumn(dateList, predictQtySumMap));
        dto.setConfirmQty(getAllColumn(dateList, confirmQtySumMap));
        dto.setLastConfirmQty(getAllColumn(dateList, preConfirmQtySumMap));
        dto.setSafetyStockQty(getAllColumn(dateList, safetyStockQtyMap));
        dto.setRealTimeInventory(getAllColumn(dateList, realTimeInventoryMap));
        dto.setDateList(dateList);
        return Arrays.asList(dto);
    }

    public static void main(String args[]) {
        SalesPlanInfoDTO salesPlanInfoDTO = new SalesPlanInfoDTO();
        salesPlanInfoDTO.setSkuCode("9999");
        List<SalesPlanInfoDTO> list = Arrays.asList(salesPlanInfoDTO);
        List<String> s = list.stream().map(dto -> {
            System.out.println(dto.getSkuCode());
            return dto.getSkuCode();
        }).collect(Collectors.toList());
        System.out.println(s);
    }

    @Override
    public ExcelExportDataDTO exportExcel(SalesPlanDTO salesPlanDTO, Integer type) {
        //指标名称集合
        List<String> allTargetsDesc = DemandPlanTargetEnum.getAllTargetsDesc();
        //获取日期标题
        List<String> dateTitles = MyDateUtil.processCyclesDate(salesPlanDTO.getWeekDateList(), "MM.dd");
        List<SalesPlanInfoDTO> salesPlanInfoDTOList = new ArrayList<>();
        List<List<Object>> exportDataList = null;
        Long userId = salesPlanDTO.getCreator();
        //获取当前用户角色权限
        List<RoleAuthorityAreaDTO> roleAreaList = roleAuthorityAreaRepository.listByUserId(userId);
        if (CollectionUtils.isEmpty(roleAreaList)) {
            throw new RomeException(ResponseMsg.FAIL_2004.getCode(), ResponseMsg.FAIL_2004.getMsg());
        }
        //渠道不为空为其他渠道计划用户
        roleAreaList = roleAreaList.stream().filter(item -> ObjectUtil.isNotNull(item.getChannelCode())).collect(Collectors.toList());
        List<String> channels = new ArrayList<>();
        roleAreaList.forEach(item -> {
            String channel = item.getChannelCode();
            channels.add(channel);
        });
        //高级搜索不选择渠道，查询用户对应渠道
        if (CollectionUtils.isEmpty(salesPlanDTO.getChannelCodeList())) {
            salesPlanDTO.setChannelCodeList(channels);
        }
        //当前页数据导出&&全部数据导出
        if (ExcelExportTypeEnum.CURRENT_PAGE_EXPORT.getType().equals(type)
                || ExcelExportTypeEnum.SEARCHED_DATA_EXPORT.getType().equals(type)) {
            PageInfo<SalesPlanInfoDTO> pageInfo = this.listWeekBySelective(salesPlanDTO);
            salesPlanInfoDTOList = pageInfo.getList();
        }
        // TODO: 2020/11/3 导出选中的数据
/*        if (ExcelExportTypeEnum.CHECKED_BOX_EXPORT.getType().equals(type)) {
            DemandPlanDO demandPlanDO = dealData(demandPlanConvertor.dtoToDO(demandPlanDTO.getDemandPlanDTOS()), demandPlanDTO);
            demandPlanDTOList = demandPlanRepository.listSalesAndDirectTarget(demandPlanDO);
        }*/
        if (CollectionUtils.isEmpty(salesPlanInfoDTOList)) {
            throw new RomeException(ResponseMsg.FAIL_2005.getCode(), ResponseMsg.FAIL_2005.getMsg());
        }
        //全部数据导出
        exportDataList = this.getExcelTargetList(salesPlanInfoDTOList, allTargetsDesc, dateTitles);
        //获取excel标题 同时返回高级搜索标题的数量
        List<List<String>> heads = new ArrayList<>();
        int mergeCellsColumns = this.setExcelTitles(heads, dateTitles);
        return ExcelExportUtil.getExcelExportData(mergeCellsColumns, exportDataList, heads, allTargetsDesc.size(), new GeneralCellWriteHandler());
    }

    /**
     * Excel中的每条数据
     *
     * @param targetList
     * @param targets
     * @param dateTitles
     * @return
     */
    private List<List<Object>> getExcelTargetList(List<SalesPlanInfoDTO> targetList, List<String> targets, List<String> dateTitles) {
        //获取excel数据
        List<List<Object>> exportDataList = new ArrayList<>();
        targetList.forEach(item -> {
            for (int i = 0; i < targets.size(); i++) {
                List<Object> itemRow = new ArrayList<>();
                //加入渠道，区域，品类，商品  信息
                this.setExcelRowAdvancedSearchCondition(item, itemRow);
                //加入指标
                String targetName = targets.get(i);
                itemRow.add(targetName);
                //加入数据
                for (int j = 0; j < dateTitles.size(); j++) {
                    if (DemandPlanTargetEnum.SALES_PLAN_AMOUNT.getDesc().equals(targetName)){
                        itemRow.add(item.getSalesPlanAmount().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getSalesPlanAmount().get(j));
                    }else if(DemandPlanTargetEnum.FORECAST_PLAN_AMOUNT.getDesc().equals(targetName)){
                        itemRow.add(item.getForecastPlanAmount().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getForecastPlanAmount().get(j));
                    }else if(DemandPlanTargetEnum.SALES_PLAN_QTY.getDesc().equals(targetName)){
                        itemRow.add(item.getSalesPlanQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getSalesPlanQty().get(j));
                    }else if(DemandPlanTargetEnum.FORECAST_PLAN_QTY.getDesc().equals(targetName)){
                        itemRow.add(item.getForecastPlanQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getForecastPlanQty().get(j));
                    }else if(DemandPlanTargetEnum.LAST_CONFIRM_QTY.getDesc().equals(targetName)){
                        itemRow.add(item.getLastConfirmQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getLastConfirmQty().get(j));
                    }else if(DemandPlanTargetEnum.SAFETY_STOCK_QTY.getDesc().equals(targetName)){
                        itemRow.add(item.getSafetyStockQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getSafetyStockQty().get(j));
                    }else if(DemandPlanTargetEnum.RESERVE_PURCHASE_QTY.getDesc().equals(targetName)){
                        itemRow.add(item.getReservePurchaseQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getReservePurchaseQty().get(j));
                    }else if(DemandPlanTargetEnum.ACTUAL_SALES_QTY.getDesc().equals(targetName)){
                        itemRow.add(item.getActualSalesQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getActualSalesQty().get(j));
                    }else if(DemandPlanTargetEnum.NO_FULFIL_PURCHASE_QTY.getDesc().equals(targetName)){
                        itemRow.add(item.getNoFulfilPurchaseQty().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getNoFulfilPurchaseQty().get(j));
                    }else if(DemandPlanTargetEnum.REAL_TIME_INVENTORY.getDesc().equals(targetName)){
                        itemRow.add(item.getRealTimeInventory().get(j).compareTo(BigDecimal.ZERO) == 0 ? "-" : item.getRealTimeInventory().get(j));
                    }
                }
                exportDataList.add(itemRow);
            }
        });
        return exportDataList;
    }

    /**
     * excel每行数据设置 高级搜索  信息
     *
     * @param salesPlanInfoDTO
     * @param itemRow
     * @return void
     **/
    private void setExcelRowAdvancedSearchCondition(SalesPlanInfoDTO salesPlanInfoDTO, List<Object> itemRow) {
        itemRow.add(salesPlanInfoDTO.getChannel());
        itemRow.add(salesPlanInfoDTO.getArea());
        itemRow.add(salesPlanInfoDTO.getCategory());
        itemRow.add(salesPlanInfoDTO.getSkuName() + "/" + salesPlanInfoDTO.getSkuCode());
    }

    private int setExcelTitles(List<List<String>> heads, List<String> dateTitles) {
        //获取高级搜索标题
        this.getExcelAdvancedSearchTitle(heads);
        int result = heads.size();
        //加入指标标题
        List<String> targetTitle = new ArrayList<>();
        targetTitle.add(ExcelExportTitleEnum.TARGET_TITLE.getTitle());
        heads.add(targetTitle);
        //加入日期标题
        AdvancedSearchUtil.getExcelDateTitle(heads, dateTitles);
        return result;
    }

    /**
     * Excel表头
     * @param heads
     */
    private void getExcelAdvancedSearchTitle(List<List<String>> heads) {
        setList(heads, ExcelExportTitleEnum.CHANNEL_TITLE.getTitle());
        setList(heads, ExcelExportTitleEnum.AREA_TITLE.getTitle());
        setList(heads, ExcelExportTitleEnum.CATEGORY_TITLE.getTitle());
        setList(heads, ExcelExportTitleEnum.SKU_TITLE.getTitle());
    }

    /**
     * 获取标题行list
     * @param heads
     * @param title
     */
    private static void setList(List<List<String>> heads, String title) {
        List<String> list = new ArrayList<>();
        list.add(title);
        heads.add(list);
    }

}
